package boardgamer.yavalath.client;

import android.os.AsyncTask;
import android.os.Environment;
import boardgamer.yavalath.common.YavalathGameServer;
import boardgamer.yavalath.common.YavalathReplay;

import javax.annotation.Nullable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * @author garysoed
 */
public class YavalathReplaySaver {

  public static final String ROOT_DIRECTORY = Environment.DIRECTORY_DOWNLOADS;
  public static final String EXTENSION = ".rpyav";

  private final YavalathGameServer server;

  public YavalathReplaySaver(YavalathGameServer server) {
    this.server = checkNotNull(server, "server");
  }

  public void save(String fileName, SaveCompleteHandler completeHandler) {
    new ReplayTask(server, completeHandler).execute(fileName);
  }
  
  public interface SaveCompleteHandler {
    void onComplete(String fileName);

    void onFailure(Exception exception);
  }
  
  private static class ReplayResult {
    
    @Nullable private final String fileName;
    @Nullable private final Exception exception;
    
    private ReplayResult(@Nullable String fileName, @Nullable Exception exception) {
      this.fileName = fileName;
      this.exception = exception;
    }
    
    public boolean isSuccess() {
      return fileName != null;
    }
    
    public String getFileName() {
      checkNotNull(fileName, "Can only call getFileName for a successful result");
      return fileName;
    }

    public Exception getException() {
      checkNotNull(exception, "Can only call getException for a failed result");
      return exception;
    }
    
    public static ReplayResult success(String fileName) {
      return new ReplayResult(checkNotNull(fileName, "fileName"), (Exception) null);
    }
    
    public static ReplayResult failure(Exception exception) {
      return new ReplayResult((String) null /* fileName */, checkNotNull(exception, "exception"));
    }
  }

  private static class ReplayTask extends AsyncTask<String, Void, ReplayResult> {

    private final YavalathGameServer server;
    private final SaveCompleteHandler completeHandler;

    public ReplayTask(YavalathGameServer server, SaveCompleteHandler completeHandler) {
      super();
      this.server = checkNotNull(server, "server");
      this.completeHandler = checkNotNull(completeHandler, "completeHandler");
    }

    @Override
    protected ReplayResult doInBackground(String... args) {
      YavalathReplay replay = server.getReplay();
      String externalStorageState = Environment.getExternalStorageState();
      if (externalStorageState.equals(Environment.MEDIA_MOUNTED)) {
        File root = Environment.getExternalStoragePublicDirectory(ROOT_DIRECTORY);
        root.mkdirs();

        // Rename the file so it's unique
        String fileName = args[0];
        for (int i = 0; new File(root, fileName + EXTENSION).exists(); i++) {
          fileName = args[0] + " (" + i + ")";
        }
        File replayFile = new File(root, fileName + EXTENSION);

        FileOutputStream fileOutputStream = null;
        try {
          replayFile.createNewFile();
          fileOutputStream = new FileOutputStream(replayFile);
          ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
          objectOutputStream.writeObject(replay);
          objectOutputStream.flush();
        } catch (IOException exception) {
          return ReplayResult.failure(exception);
        } finally {
          try {
            if (fileOutputStream != null) {
              fileOutputStream.close();
            }
          } catch (IOException e) {
            return ReplayResult.failure(e);
          }
        }
        
        return ReplayResult.success(replayFile.getAbsolutePath());
      } else {
        return ReplayResult.failure(new IOException("External storage unavailable"));
      }
    }

    @Override
    protected void onPostExecute(ReplayResult result) {
      if (result.isSuccess()) {
        completeHandler.onComplete(result.getFileName());
      } else {
        completeHandler.onFailure(result.getException());
      }
    }
  }
}
